import { Op } from 'sequelize';
import Job from '@/models/monitor/job.model';
import SchedulerUtils from '@/utils/job/scheduler.util';
import CronUtils from '@/utils/job/cron.util';
import { PaginationParams } from '@/types';
import { CronExpressionParser } from 'cron-parser';
import { getLogger } from '@/utils/logger';

// 创建常规日志记录器（不输出到控制台）
const logger = getLogger("job-service", {
  console: false,
});
// 创建控制台日志记录器
const consoleLogger = getLogger("job-service");

/**
 * 定时任务服务类
 */
class JobService {
  /**
   * 查询任务列表
   * @param query 查询参数
   * @returns 任务列表
   */
  public async selectJobList(query: any): Promise<any[]> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`查询任务列表: ${JSON.stringify(query)}`);
      
      const { jobName, jobGroup, status, invokeTarget, createBy } = query;
      const where: any = {};

      if (jobName) {
        where.jobName = { [Op.like]: `%${jobName}%` };
      }
      if (jobGroup) {
        where.jobGroup = jobGroup;
      }
      if (status) {
        where.status = status;
      }
      if (invokeTarget) {
        where.invokeTarget = { [Op.like]: `%${invokeTarget}%` };
      }
      if (createBy) {
        where.createBy = { [Op.like]: `%${createBy}%` };
      }

      const jobs = await Job.findAll({
        where,
        order: [['createTime', 'DESC']]
      });
      
      // 动态计算下次执行时间
      const result = jobs.map(job => {
        const jobObj: any = job.toJSON();
        try { 
          const interval = CronExpressionParser.parse(jobObj.cronExpression, { currentDate: new Date() });
          jobObj.nextValidTime = interval.next().toDate();
        } catch (e) {
          logger.warn(`计算任务下次执行时间失败: jobId=${jobObj.jobId}, cronExpression=${jobObj.cronExpression}`);
          jobObj.nextValidTime = null;
        }
        return jobObj;
      });
      
      // 记录查询结果
      logger.info(`任务列表查询完成: 总数=${result.length}`);
      
      return result;
    } catch (error) {
      consoleLogger.error(`查询任务列表失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('查询任务列表失败');
    }
  }

  /**
   * 查询任务分页列表
   * @param query 查询参数
   * @returns 任务分页列表
   */
  public async getJobListPaged(query: PaginationParams): Promise<{ rows: any[], count: number }> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`查询任务分页列表: ${JSON.stringify(query)}`);
      
      const { pageNum = 1, pageSize = 10, ...filters } = query;
      const offset = (pageNum - 1) * pageSize;
      const limit = pageSize;
      
      const where: any = {};
      const { jobName, jobGroup, status, invokeTarget, createBy } = filters;

      if (jobName) {
        where.jobName = { [Op.like]: `%${jobName}%` };
      }
      if (jobGroup) {
        where.jobGroup = jobGroup;
      }
      if (status) {
        where.status = status;
      }
      if (invokeTarget) {
        where.invokeTarget = { [Op.like]: `%${invokeTarget}%` };
      }
      if (createBy) {
        where.createBy = { [Op.like]: `%${createBy}%` };
      }

      const { rows, count } = await Job.findAndCountAll({
        where,
        order: [['createTime', 'DESC']],
        offset,
        limit
      });
      
      // 动态计算下次执行时间
      const dataRows = rows.map(job => {
        const jobObj: any = job.toJSON();
        try {
          const interval = CronExpressionParser.parse(jobObj.cronExpression, { currentDate: new Date() });
          jobObj.nextValidTime = interval.next().toDate();
        } catch (e) {
          logger.warn(`计算任务下次执行时间失败: jobId=${jobObj.jobId}, cronExpression=${jobObj.cronExpression}`);
          jobObj.nextValidTime = null;
        }
        return jobObj;
      });
      
      // 记录查询结果
      logger.info(`任务分页列表查询完成: 总数=${count}, 当前页=${pageNum}, 每页大小=${pageSize}`);
      
      return { rows: dataRows, count };
    } catch (error) {
      consoleLogger.error(`查询任务分页列表失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('查询任务分页列表失败');
    }
  }

  /**
   * 通过ID查询单条任务数据
   * @param jobId 任务ID
   * @returns 任务信息
   */
  public async selectJobById(jobId: number): Promise<any> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`根据ID查询任务: jobId=${jobId}`);
      
      const job = await Job.findByPk(jobId);
      if (!job) {
        logger.info(`未找到任务: jobId=${jobId}`);
        return null;
      }
      
      const jobObj: any = job.toJSON();
      try {
        const interval = CronExpressionParser.parse(jobObj.cronExpression, { currentDate: new Date() });
        jobObj.nextValidTime = interval.next().toDate();
      } catch (e) {
        logger.warn(`计算任务下次执行时间失败: jobId=${jobObj.jobId}, cronExpression=${jobObj.cronExpression}`);
        jobObj.nextValidTime = null;
      }
      
      // 记录查询结果
      logger.info(`任务查询成功: jobId=${jobId}, jobName=${jobObj.jobName}`);
      
      return jobObj;
    } catch (error) {
      consoleLogger.error(`根据ID查询任务失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('查询任务信息失败');
    }
  }

  /**
   * 新增任务
   * @param job 任务信息
   * @returns 结果
   */
  public async insertJob(job: Job): Promise<number> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`新增任务: jobName=${job.jobName}, jobGroup=${job.jobGroup}`);
      
      // 验证cron表达式
      if (!CronUtils.isValid(job.cronExpression)) {
        consoleLogger.error(`Cron表达式不正确: ${job.cronExpression}`);
        throw new Error('Cron表达式不正确');
      }
      
      // 验证invokeTarget是否在白名单中
      if (!SchedulerUtils.whiteList(job.invokeTarget)) {
        consoleLogger.error(`目标字符串不在白名单内: ${job.invokeTarget}`);
        throw new Error('目标字符串不在白名单内');
      }
      
      // 检查调用目标是否包含禁止的字符串
      const dangerPatterns = ['rmi', 'ldap', 'ldaps', 'http', 'https'];
      if (dangerPatterns.some(pattern => job.invokeTarget.toLowerCase().includes(pattern))) {
        consoleLogger.error(`目标字符串包含禁止的模式: ${job.invokeTarget}`);
        throw new Error(`目标字符串不允许包含: ${dangerPatterns.join(', ')}`);
      }
      
      // 写入数据库
      const createdJob = await Job.create(job);
      
      // 添加到任务调度器
      if (createdJob.status === '0') {
        logger.debug(`添加任务到调度器: jobId=${createdJob.jobId}, jobName=${createdJob.jobName}`);
        await SchedulerUtils.createScheduleJob(createdJob);
      }
      
      // 记录操作结果
      logger.info(`任务新增成功: jobId=${createdJob.jobId}, jobName=${createdJob.jobName}`);
      
      return createdJob.jobId;
    } catch (error) {
      consoleLogger.error(`新增任务失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error; // 保留原始错误信息
    }
  }

  /**
   * 修改任务
   * @param job 任务信息
   * @returns 结果
   */
  public async updateJob(job: Job): Promise<number> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`修改任务: jobId=${job.jobId}, jobName=${job.jobName}`);
      
      // 验证cron表达式
      if (!CronUtils.isValid(job.cronExpression)) {
        consoleLogger.error(`Cron表达式不正确: ${job.cronExpression}`);
        throw new Error('Cron表达式不正确');
      }
      
      // 验证invokeTarget是否在白名单中
      if (!SchedulerUtils.whiteList(job.invokeTarget)) {
        consoleLogger.error(`目标字符串不在白名单内: ${job.invokeTarget}`);
        throw new Error('目标字符串不在白名单内');
      }
      
      // 检查调用目标是否包含禁止的字符串
      const dangerPatterns = ['rmi', 'ldap', 'ldaps', 'http', 'https'];
      if (dangerPatterns.some(pattern => job.invokeTarget.toLowerCase().includes(pattern))) {
        consoleLogger.error(`目标字符串包含禁止的模式: ${job.invokeTarget}`);
        throw new Error(`目标字符串不允许包含: ${dangerPatterns.join(', ')}`);
      }
      
      // 先获取原任务信息
      const originalJob = await Job.findByPk(job.jobId);
      if (!originalJob) {
        consoleLogger.error(`任务不存在: jobId=${job.jobId}`);
        throw new Error('任务不存在');
      }
      
      // 判断cron表达式是否有更改
      const cronChanged = originalJob.cronExpression !== job.cronExpression;
      // 判断是否在运行（status=0）
      const isActive = originalJob.status === '0';
      
      // 更新数据库
      const [rows] = await Job.update(job, {
        where: { jobId: job.jobId }
      });
      
      // 重新获取最新的任务数据
      const updatedJob = await Job.findByPk(job.jobId);
      
      // 调度任务逻辑
      if (updatedJob) {
        logger.debug(`更新任务调度: jobId=${job.jobId}, cronChanged=${cronChanged}, isActive=${isActive}, newStatus=${job.status}`);
        
        // 逻辑：如表达式变且在运行，则先删再加，否则只调度
        if (cronChanged && isActive && job.status === '0') {
          logger.debug(`Cron表达式已更改，重新调度任务: jobId=${job.jobId}`);
          SchedulerUtils.deleteJob(originalJob);
          await SchedulerUtils.createScheduleJob(updatedJob);
        } else if (job.status === '0') {
          logger.debug(`启用任务调度: jobId=${job.jobId}`);
          await SchedulerUtils.createScheduleJob(updatedJob);
        } else {
          logger.debug(`停用任务调度: jobId=${job.jobId}`);
          SchedulerUtils.deleteJob(updatedJob);
        }
      }
      
      // 记录操作结果
      logger.info(`任务修改完成: jobId=${job.jobId}, 影响行数=${rows}`);
      
      return rows;
    } catch (error) {
      consoleLogger.error(`修改任务失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error; // 保留原始错误信息
    }
  }

  /**
   * 修改任务状态
   * @param job 任务信息
   * @returns 结果
   */
  public async changeStatus(job: Job): Promise<number> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`修改任务状态: jobId=${job.jobId}, status=${job.status}`);
      
      // 先获取原任务信息
      const originalJob = await Job.findByPk(job.jobId);
      if (!originalJob) {
        consoleLogger.error(`任务不存在: jobId=${job.jobId}`);
        throw new Error('任务不存在');
      }
      
      // 更新数据库中的状态
      const [rows] = await Job.update(
        { status: job.status },
        { where: { jobId: job.jobId } }
      );
      
      // 根据新状态修改任务调度
      if (job.status === '0') {
        // 如果是启用任务
        logger.debug(`启用任务调度: jobId=${job.jobId}, jobName=${originalJob.jobName}`);
        originalJob.status = '0';
        await SchedulerUtils.createScheduleJob(originalJob);
      } else {
        // 如果是停止任务
        logger.debug(`停用任务调度: jobId=${job.jobId}, jobName=${originalJob.jobName}`);
        originalJob.status = '1';
        SchedulerUtils.deleteJob(originalJob);
      }
      
      // 记录操作结果
      logger.info(`任务状态修改完成: jobId=${job.jobId}, status=${job.status}, 影响行数=${rows}`);
      
      return rows;
    } catch (error) {
      consoleLogger.error(`修改任务状态失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('修改任务状态失败');
    }
  }

  /**
   * 立即执行一次任务
   * @param job 任务信息
   * @returns 结果
   */
  public async run(job: Job): Promise<boolean> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`立即执行任务: jobId=${job.jobId}`);
      
      // 获取完整任务信息
      const jobInfo = await Job.findByPk(job.jobId);
      if (!jobInfo) {
        logger.warn(`未找到任务: jobId=${job.jobId}`);
        return false;
      }
      
      // 立即执行任务
      logger.debug(`执行任务: jobId=${jobInfo.jobId}, jobName=${jobInfo.jobName}, invokeTarget=${jobInfo.invokeTarget}`);
      const result = await SchedulerUtils.runOnce(jobInfo);
      
      // 记录操作结果
      logger.info(`任务执行完成: jobId=${job.jobId}, 执行结果=${result}`);
      
      return result;
    } catch (error) {
      consoleLogger.error(`立即执行任务失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('立即执行任务失败');
    }
  }

  /**
   * 删除任务
   * @param jobIds 需要删除的任务ID数组
   * @returns 结果
   */
  public async deleteJobByIds(jobIds: number[]): Promise<number> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`删除任务: jobIds=${JSON.stringify(jobIds)}`);
      
      // 先查询所有要删除的任务
      const jobs = await Job.findAll({
        where: { jobId: jobIds }
      });
      
      // 从调度器中删除任务
      for (const job of jobs) {
        logger.debug(`从调度器中删除任务: jobId=${job.jobId}, jobName=${job.jobName}`);
        SchedulerUtils.deleteJob(job);
      }
      
      // 从数据库中删除任务
      const result = await Job.destroy({
        where: { jobId: jobIds }
      });
      
      // 记录操作结果
      logger.info(`任务删除完成: 删除数量=${result}, 请求删除数量=${jobIds.length}`);
      
      return result;
    } catch (error) {
      consoleLogger.error(`删除任务失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('删除任务失败');
    }
  }

  /**
   * 初始化任务调度器
   */
  public async initScheduler(): Promise<void> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info('初始化任务调度器');
      
      await SchedulerUtils.initScheduler();
      
      // 记录操作结果
      logger.info('任务调度器初始化完成');
    } catch (error) {
      consoleLogger.error(`初始化任务调度器失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('初始化任务调度器失败');
    }
  }
}

export default new JobService(); 